package wmhsudoku.gui;

import java.awt.BorderLayout;
import java.awt.Checkbox;
import java.awt.Component;
import java.awt.ComponentOrientation;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.HeadlessException;
import java.awt.Insets;
import java.awt.LayoutManager;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.text.NumberFormat;

import javax.swing.BoxLayout;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFormattedTextField;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JSpinner;
import javax.swing.JToolBar;

import wmhsudoku.board.Map;



public class MainFrame extends JFrame implements WindowListener, ActionListener {
	
	final int MIN_WIDTH = 502;				// window size, width
	final int MIN_HEIGHT = 600;				// window size, height
	private final int X = 100;
	private final int Y = 50;
	private LayoutManager layoutManager;
	private GamePanel gamePanel;
	
	private Map map = null;
	private Main main;
	
	public static final int DEF_FIELD_SIZE = 9;
	private int fieldSize = DEF_FIELD_SIZE;
	
	JSpinner sizeSpinner;

	private Map mask;
	
	private static final String START = "New";
	private static final String SOLVE = "Solve";
	private static final String STOP = "Stop calculations";
	private static final String BRUTE_FORCE_ALGORITHM = "Brute Force";
	private static final String ANNEALING_ALGORITHM = "Simulated Annealing";
	
    private JRadioButton rbA, rbB;
    private JRadioButton rBtnLinear, rBtnExp;
	private NumberFormat numberFormat;
	private JFormattedTextField tfInitTemp;
	private JFormattedTextField tfChangeTemp;
	private JFormattedTextField tfNeighNumber;
	private JCheckBox chbConsolePrint;
	private JCheckBox chbFilePrint;
	private JRadioButton rbtnNeighLinear;
	private JRadioButton rbtnNeighConstans;	
	private JButton btnNew;
	private JButton btnSolve;
	
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	public MainFrame(final Main main) throws HeadlessException {
		this.setLocation(new Point(X, Y));
		this.setMinimumSize(new Dimension(MIN_WIDTH,MIN_HEIGHT)); 	// sets minimum frame size
		this.setTitle("WMH Sudoku");								//set frame title
		this.main = main;
		layoutManager=new BorderLayout(); 
		setLayout(layoutManager);
		setDefaultCloseOperation(EXIT_ON_CLOSE);
	
		gamePanel = new GamePanel(this);
		getContentPane().add(gamePanel,BorderLayout.CENTER); // in the center of the frame
				
		// toolbar
	    Container panel = new Container();
	    panel.setLayout(new GridBagLayout());
	    panel.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT);
	    GridBagConstraints c = new GridBagConstraints();
	
	    c.fill = GridBagConstraints.HORIZONTAL;

	    // 1 row
	    JLabel lbAlgorithm = new JLabel("Algorithm: ");
	    fillGrid(c, 0, 0);
	    panel.add(lbAlgorithm, c);
	    rbA = new JRadioButton("Annealing", true);
	    rbA.setActionCommand(ANNEALING_ALGORITHM);
	    rbA.addActionListener(this);
	    c.gridwidth = 1;
	    fillGrid(c, 1, 0);
	    panel.add(rbA, c); 
	    rbB = new JRadioButton("Brute Force", false);
	    rbB.setActionCommand(BRUTE_FORCE_ALGORITHM);
	    rbB.addActionListener(this);
	    c.gridwidth = 1;
	    fillGrid(c, 2, 0);
	    panel.add(rbB, c);
	    ButtonGroup group = new ButtonGroup();
	    group.add(rbA);
	    group.add(rbB);	     
	    
	    // 2 row
	    JLabel lbTempChangeFunction = new JLabel("Temp. change function: ");
	    fillGrid(c, 0, 1);
	    panel.add(lbTempChangeFunction, c);
	    rBtnLinear = new JRadioButton("Linear", true);
	    fillGrid(c, 1, 1);
	    panel.add(rBtnLinear, c); 
	    rBtnExp = new JRadioButton("Exp", false);
	    fillGrid(c, 2, 1);
	    panel.add(rBtnExp, c);
	    group = new ButtonGroup();
	    group.add(rBtnLinear);
	    group.add(rBtnExp);	 	    
	    
	    // 3 row
	    JLabel lbInitTemp = new JLabel("Init temp.: ");
	    tfInitTemp = new JFormattedTextField(numberFormat);
	    tfInitTemp.setValue(new Double(0.6));
	    //tfInitTemp.setColumns(10);
	    c.gridwidth = 1;
	    fillGrid(c, 0, 2);
	    panel.add(lbInitTemp, c);
	    fillGrid(c, 1, 2);
	    c.insets = new Insets(0,0,0,5);
	    panel.add(tfInitTemp, c);

	    JLabel lbChangeTemp = new JLabel("Temp. change: ");
	    tfChangeTemp = new JFormattedTextField(numberFormat);
	    tfChangeTemp.setValue(new Double(0.0000006));
	    tfChangeTemp.setColumns(10);
	    fillGrid(c, 2, 2);
	    c.insets = new Insets(0,0,0,0);
	    panel.add(lbChangeTemp,c);
	    fillGrid(c, 3, 2);
	    panel.add(tfChangeTemp, c);
	    
	    // 4 row
	    JLabel lbNeigh = new JLabel("Neighbours: ");
	    tfNeighNumber = new JFormattedTextField(numberFormat);
	    tfNeighNumber.setValue(1);
	    tfNeighNumber.setColumns(2);
	    c.gridwidth = 1;
	    fillGrid(c, 0, 3);
	    panel.add(lbNeigh, c);
	    fillGrid(c, 1, 3);
	    panel.add(tfNeighNumber, c);

	    rbtnNeighConstans = new JRadioButton("Constant");
	    rbtnNeighConstans.setSelected(true);
	    fillGrid(c, 2, 3);
	    panel.add(rbtnNeighConstans,c);
	    rbtnNeighLinear = new JRadioButton("Linear");
	    fillGrid(c, 3, 3);
	    panel.add(rbtnNeighLinear, c);	   
	    group = new ButtonGroup();
	    group.add(rbtnNeighConstans);
	    group.add(rbtnNeighLinear);
	    
	    // 4 row
	    chbConsolePrint = new JCheckBox("Print console output");
	    chbConsolePrint.setSelected(true);
	    c.gridwidth = 2;
	    fillGrid(c, 0, 4);
	    panel.add(chbConsolePrint, c);
	    chbFilePrint = new JCheckBox("Print file output");
	    c.gridwidth = 2;
	    fillGrid(c, 2, 4);
	    panel.add(chbFilePrint, c);
	    
	    // 5 row  buttons
	    c.insets = new Insets(20,20,20,20);
	    JButton button = null;
	    btnNew = makeNavigationButton(START, "New board", "new");
	    fillGrid(c, 0, 5);
	    c.gridwidth = 1;
	    panel.add(btnNew, c);
	    btnSolve = makeNavigationButton(SOLVE, "Solve sudoku", "solve");
	    fillGrid(c, 1, 5);
	    c.gridwidth = 1;
	    panel.add(btnSolve, c);   
	    button = makeNavigationButton(STOP, "Stop calculations", "stop");
	    c.gridwidth = 2;
	    fillGrid(c, 2, 5);
	    panel.add(button,c );	    
	    
	    getContentPane().add(panel, BorderLayout.PAGE_START);
	}
	
	private void fillGrid(GridBagConstraints c, int x, int y) {
		c.fill = GridBagConstraints.HORIZONTAL;
		c.gridx = x;
		c.gridy = y;
	}
	

	public void setNewMap(Map map, Map mask) {
		this.map = map;
		this.mask = mask;
	}
	
	
	public int getFieldSize() {
		return fieldSize;
	}
	
	public Map getMap() {
		return map;
	}
	
	public Map getMask() {
		return mask;
	}


	protected JButton makeNavigationButton( String actionCommand, String toolTipText, String altText) {
		//Create and initialize the button.
		JButton button = new JButton(actionCommand);
		button.setActionCommand(actionCommand);
		button.setToolTipText(toolTipText);
		button.addActionListener(this);
		
	    return button;
	}


	@Override
	public void actionPerformed(ActionEvent e) {
	    String cmd = e.getActionCommand();

	    // Handle each button.
	    if (START.equals(cmd)) {
	    	main.newBoard(rBtnLinear.isSelected(), Double.parseDouble(tfInitTemp.getText()), 
	    			Double.parseDouble(tfChangeTemp.getText()), chbConsolePrint.isSelected(), chbFilePrint.isSelected(),
	    			Integer.parseInt(tfNeighNumber.getText()), rbtnNeighConstans.isSelected());
	    } else if (SOLVE.equals(cmd)) {
	    	main.solveBoard(rbA.isSelected(), rBtnLinear.isSelected(), Double.parseDouble(tfInitTemp.getText()), 
	    			Double.parseDouble(tfChangeTemp.getText()), chbConsolePrint.isSelected(), chbFilePrint.isSelected(),
	    			Integer.parseInt(tfNeighNumber.getText()), rbtnNeighConstans.isSelected());
	    } else if (STOP.equals(cmd)) {
	    	Main.RUNNING = false;
	    } else if (BRUTE_FORCE_ALGORITHM.equals(cmd)) {
	    	disableButtons();	    	
	    } else if (ANNEALING_ALGORITHM.equals(cmd)) {
	    	enableButtons();
	    }
	}
	
	private void disableButtons() {
    	tfChangeTemp.setEnabled(false);
    	tfInitTemp.setEnabled(false);
    	tfNeighNumber.setEnabled(false);
    	rbtnNeighConstans.setEnabled(false);
    	rbtnNeighLinear.setEnabled(false);
    	rBtnExp.setEnabled(false);
    	rBtnLinear.setEnabled(false);
    	btnNew.setEnabled(false);
	}
	
	private void enableButtons() {
    	tfChangeTemp.setEnabled(true);
    	tfInitTemp.setEnabled(true);
    	tfNeighNumber.setEnabled(true);
    	rbtnNeighConstans.setEnabled(true);
    	rbtnNeighLinear.setEnabled(true);
    	rBtnExp.setEnabled(true);
    	rBtnLinear.setEnabled(true);
    	btnNew.setEnabled(true);
	}
	
	public void disableSolveButtons() {
		btnNew.setEnabled(false);
		btnSolve.setEnabled(false);
	}
	
	public void enableSolbeButtons() {
		btnNew.setEnabled(true);
		btnSolve.setEnabled(true);		
	}
	
	public void reload() {
		gamePanel.repaint();
	}
	
	public GamePanel getGamePanel() {
		return gamePanel;
	}

	@Override
	public void windowClosing(WindowEvent e) {
		dispose();
		System.exit(0);
	}

	@Override
	public void windowActivated(WindowEvent arg0) {	}

	@Override
	public void windowClosed(WindowEvent arg0) { }

	@Override
	public void windowDeactivated(WindowEvent arg0) { }

	@Override
	public void windowDeiconified(WindowEvent arg0) { }

	@Override
	public void windowIconified(WindowEvent arg0) {	}

	@Override
	public void windowOpened(WindowEvent arg0) { }
	
}